package stc.skymobi.netty.handler.codec.memcached;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import stc.skymobi.bean.bytebean.ByteBean;
import stc.skymobi.netty.handler.codec.memcached.bean.response.BinaryResponseHeader;
import stc.skymobi.netty.handler.codec.memcached.bean.response.RetrievalResponse;
import stc.skymobi.util.ByteUtils;

import static stc.skymobi.netty.handler.codec.memcached.bean.core.BinaryCommonHeader.OPCODE_GET;

public class MemcachedResponseDecoder extends LengthFieldBasedFrameDecoder {
    private static Logger logger = LoggerFactory.getLogger(MemcachedResponseDecoder.class);

    public MemcachedResponseDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
    }

    public MemcachedResponseDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
    }

    @Override
    public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        ByteBuf buffer = (ByteBuf) super.decode(ctx, in);
        if (buffer == null) {
            return null;
        }
        byte[] bytes = new byte[buffer.readableBytes()];
        buffer.readBytes(bytes);
        if (logger.isDebugEnabled()) {
            logger.debug(ByteUtils.bytesAsHexString(bytes, 128));
        }
        byte opCode = bytes[1];
        switch (opCode) {
            case OPCODE_GET:
                return decode(bytes, RetrievalResponse.class);
            default:
                return decode(bytes, BinaryResponseHeader.class);
        }
    }

    private <T extends ByteBean> Object decode(byte[] bytes, Class<T> clazz) {
        return MemcachedNativeCodec.getBeanCodec().decode(
                MemcachedNativeCodec.getBeanCodec().getDecContextFactory().createDecContext(
                        bytes, clazz, null, null)).getValue();
    }
}
